
/**
 * 递归处理深层数组的每个对象
 * @param arr   数组
 * @param fun  回调函数
 * @param childrenField  子数组项名称
 * @param resettingReturnChildrenField 重置后的子数组项名称
 * @returns [] 数组
 * @example 
 * const res = recursionHandleEachChildArrayItem([{id:1,children:[{id:2,children:[]}]}], (item) => {
 *      return {
 *          title: item.id.toString(),
 *          icon: item.icon
 *      }
 *  }, 'children','ch')
 */
export const recursionHandleEachChildArrayItem = <
    T extends Record<string, any>
>(
    arr: T[],
    fun: (item: T) => object,
    childrenField: keyof T,
    resettingReturnChildrenField?: string
) => {
    return arr.map((item) => {
        let data: Record<string, any> = {}
        if (fun) {
            data = fun(item)
        }
        if (childrenField) {
            data[resettingReturnChildrenField || childrenField.toString()] = item[childrenField] ? item[childrenField].length ? recursionHandleEachChildArrayItem(item[childrenField], fun, childrenField, resettingReturnChildrenField) : [] : null
        }
        return data
    })
}

/**
 * 数组对象根据自定义字段进行去重
 * @param arr 数组
 * @param field  字段名
 * @returns [] 数组
 * @example const res = arrDistinctByField([{name:'小明'},{name:'小明'}], 'name')
 */
export const arrDistinctByField = <
    T extends Record<string, any>
>(
    arr: T[],
    field: keyof T
) => {
    return arr.filter((item, index, self) => {
        return self.findIndex(el => el[field] == item[field]) === index
    })
}

/**
 * 对象数组分组 (数组)
 * @description 将对象数组分组排列到新对象数组中childrenField传参字段内
 * @param arr 数组
 * @param field 子数组项名称
 * @param key 分组结果字段
 * @param childrenField 分组结果子数组项字段
 * @returns [] 数组
 * @example const res = setArrToObjectGroups([{sex:'男'},{sex:'女'}], 'sex')
 */
export const setArrToObjectGroups = <
    T extends Record<string, any>,
    K extends keyof T
>(
    arr: T[],
    field: K,
    key: string = 'key',
    childrenField: string = 'children'
) => {
    const map = new Map<K, T>()
    arr.forEach((item, index, arr) => {
        if (!map.has(item[field])) {
            map.set(
                item[field],
                arr.filter(a => a[field] == item[field]) as any
            )
        }
    })
    return Array.from(map).map(item => {
        return {
            [key]: item[0],
            [childrenField]: item[1]
        }
    })
}

/**
 * 对象数组分组 (数组)
 * @description 将对象数组分组排列到新数组中的数组
 * @param arr 数组
 * @param field 子数组项名称
 * @returns [] 数组
 * @example const res = setArrToArrGroups([{sex:'男'},{sex:'女'}], 'sex')
 */
export const setArrToArrGroups = <
    T extends Record<string, any>,
    K extends keyof T
>(
    arr: T[],
    field: K
) => {
    const map = new Map<K, T>()
    arr.forEach((item, index, arr) => {
        if (!map.has(item[field])) {
            map.set(
                item[field],
                arr.filter(a => a[field] == item[field]) as any
            )
        }
    })
    return Array.from(map).map(item => [item[1]])
}

/**
 * 获取数组中的最大深度
 * @param arr 数组
 * @param childrenField 子数组项名称
 * @returns 深度数值
 * @example const res = getArrMaxDepth([{children:[{children:[]}]}], 'children')
 */
export const getArrMaxDepth = <
    T extends Record<string, any>
>(
    arr: T[],
    childrenField: keyof T
) => {
    let maxDepth = 0
    arr.forEach(item => {
        if (item[childrenField].length) {
            maxDepth = Math.max(maxDepth, getArrMaxDepth(item.children, childrenField))
        }
    })
    return maxDepth + 1
}

/**
 * 扁平数组转树形数组
 * @param list 数组
 * @param id 唯一标识字段
 * @param pid 父级标识字段
 * @returns [] 数组
 * @example const res = flatArrToTreeArr([{id:1,pid:0},{id:2,pid:1},{id:3,pid:0}], 'id', 'pid')
 */
export const flatArrToTreeArr = <
    T extends Record<string, any>,
    I extends keyof T,
    P extends Exclude<keyof T, I>
>(
    list: T[],
    id: I,
    pid: P
) => {
    let map = {} as Record<string, any>;
    let val = [] as T[];
    list.forEach((item, index) => {
        map[item[id]] = item;
    });
    list.forEach((item, index) => {
        let parent = map[item[pid]];
        if (parent) {
            (parent.children || (parent.children = [])).push(item);
        } else {
            val.push(item);
        }
    });
    return val;
};

/**
 * 树形数组转扁平数组
 * @param tree 数组
 * @param childrenField 子数据字段
 * @returns [] 数组
 * @example const res = treeArrToFlatArr([{id:1,pid:0,children:[{id:2,pid:1}]},{id:3,pid:0}], 'children')
 */
export const treeArrToFlatArr = <
    T extends Record<string, any>,
    C extends keyof T
>(
    tree: T[],
    childrenField: C
) => {
    let res = [] as T[]
    tree.forEach(el => {
        res.push(el)
        el[childrenField] && res.push(...treeArrToFlatArr(el[childrenField] as T[], childrenField))
    })
    return res
}

/**
 * 判断是有效的url
 * @param url 网址
 * @returns true/false
 * @example const explorer = isHttp('https://www.example.com')
 */
export const isHttp = (url: string) => {
    return /^(http|https):\/\//.test(url)
}

/**
 * 获取当前浏览器名称
 * @returns 浏览器名称
 * @example const explorer = getExplorer()
 */
export const getExplorer = () => {
    const ua = window.navigator.userAgent
    const isExplorer = (exp: string) => {
        return ua.indexOf(exp) > -1
    }
    if (isExplorer('MSIE')) return 'IE'
    else if (isExplorer('Firefox')) return 'Firefox'
    else if (isExplorer('Chrome')) return 'Chrome'
    else if (isExplorer('Opera')) return 'Opera'
    else if (isExplorer('Safari')) return 'Safari'
}

/**
 * 绑定事件
 * @description 解绑事件 on(element, event, handler)
 */
export const on2 = (element: Element, event: keyof DocumentEventMap, handler: EventListenerOrEventListenerObject) => {
    if (element && event && handler) {
        return element.addEventListener(event, handler, false)
    }
}

/**
 * 解绑事件
 * @description 解绑事件 off(element, event, handler)
 */
export const off = (element: Element, event: keyof DocumentEventMap, handler: EventListenerOrEventListenerObject) => {
    if (element && event) {
        return element.removeEventListener(event, handler, false)
    }
}

/**
 * 随机数字
 * @param min 最小值
 * @param max 最大值
 * @returns number 随机数
 */
export const randomNum = (min: number, max: number) => {
    return Math.floor(Math.random() * (max - min + 1) + min);
}

/**
 * 随机汉字与字母
 * @param str 汉字与字母的组合
 * @param len 长度
 * @param isUpper 是否大写
 */
export const randomStr = (str: string, len: number, isUpper: boolean = false) => {
    let result = '';
    for (let i = 0; i < len; i++) {
        let random = randomNum(0, str.length - 1);
        result += str.charAt(random);
    }
    if (isUpper) {
        return result.toUpperCase();
    }
    return result;
}
/**
 * 链接GET参数转对象
 * @param url 链接
 * @example cosnt obj = urlParamToObject('www.example.com?key=1&key2=2')
 */
export const urlParamToObject = (url: string) => {
    let obj: Record<string, any> = {}
    if (url.indexOf("?") < 0) return obj
    const str = url.split("?")[1].split("&")
    for (var i = 0; i < str.length; i++) {
        var a = str[i].split('=')
        obj[a[0]] = a[1]
    }
    return obj
}

/**
 * 获取GET链接某个参数的值
 * @param url 链接
 * @example const key = getUrlParamVal('www.example.com?key=1&key2=2','key')
 */
export const getUrlParamVal = (url: string, key: string) => {
    const obj = urlParamToObject(url)
    return obj[key] ?? null
}

/**
 * 完成url拼接参数
 * @param url 链接
 * @param param 新参数对象
 * @example const url = createUrl('www.example.com',{key:'1',key2:'2'})
 */
export const createUrl = (url: string, param: Record<string, any>) => {
    let tmp = ''
    const obj = {
        ...urlParamToObject(url),
        ...param
    }
    for (let k in obj) {
        let value = obj[k] !== undefined ? obj[k] : ''
        tmp += '&' + k + '=' + encodeURIComponent(value)
    }
    let domain = getDomainUrl(url)
    return domain + '?' + tmp.slice(1);
}

/**
 * 获取域名
 * @param url 
 * @param param 
 * @returns 
 */
export const getDomainUrl = (url: string) => {
    let webUrl = url.indexOf('?') ? url.split("?")[0] : url
    return webUrl;
}

/**
 * 获取最后一页实例
 * @example const page = getLastPageInstance()
 */
export const getLastPageInstance = () => {
    const pages = getCurrentPages();
    return pages[pages.length - 1];
}

/**
 * 获取当前页不带参数的路由
 * @example const url = getRoute()
 */
export const getRoute = () => {
    const page = getLastPageInstance()
    let route = '';
    route = `/${page.route?.split('?')[0]}`;
    return route;
}

/**
 * 获取当前页带参数的路由
 * @example const url = getRouteWithOption()
 */
export const getRouteWithOption = () => {
    const page = getLastPageInstance() as any
    let route = '';
    route = `/${page.route?.split('?')[0]}`;
    if (page.options && Object.keys(page.options).length) {
        route = createUrl(route, page.options)
    }
    return route;
}

/**
 * 格式化金额
 * @param val 
 * @param opt 
 * @returns 
 */
export const priceFilter = (
    val: string | number,
    opt = {
        /**金额是否需要除以100 */
        mountType: true
    }
) => {
    val = +val
    if (!opt.mountType) {
        return val.toFixed(2);
    } else {
        return (val / 100).toFixed(2);
    }
}